package com.eduagent.xwqeduagent.tools;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.StrUtil; // StrUtil 用于字符串判断
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpRequest;
import com.eduagent.xwqeduagent.constant.FileConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.regex.Pattern;

public class ResourceDownloadTool {

    private static final Logger logger = LoggerFactory.getLogger(ResourceDownloadTool.class);
    private static final int DEFAULT_TIMEOUT = 60000; // 60 秒超时
    // 定义一个正则表达式，匹配大多数操作系统中文件名不允许的字符
    // 包括： \ / : * ? " < > | 以及控制字符 (ASCII 0-31)
    private static final Pattern INVALID_FILENAME_CHARS_PATTERN = Pattern.compile("[\\\\/:*?\"<>|\\x00-\\x1F]");
    private static final String REPLACEMENT_CHAR = "_"; // 用于替换非法字符的字符

    /**
     * 清理文件名中的非法字符。
     *
     * @param fileName 原始文件名
     * @return 清理后的文件名
     */
    private String sanitizeFileName(String fileName) {
        if (fileName == null || fileName.trim().isEmpty()) {
            return "default_filename";
        }
        // 替换所有匹配到的非法字符
        String sanitized = INVALID_FILENAME_CHARS_PATTERN.matcher(fileName).replaceAll(REPLACEMENT_CHAR);
        // 避免文件名以点或空格开头或结尾（某些系统不允许）
        sanitized = sanitized.trim();
        while (sanitized.startsWith(".")) {
            sanitized = sanitized.substring(1);
        }
        while (sanitized.endsWith(".")) {
            sanitized = sanitized.substring(0, sanitized.length() - 1);
        }
        // 如果清理后文件名变为空（例如，原文件名只包含非法字符），则提供一个默认名
        if (sanitized.trim().isEmpty()) {
            return "sanitized_default_" + System.currentTimeMillis();
        }
        return sanitized;
    }

    @Tool(description = "从给定的 URL 下载资源。可以选择提供特定的文件名。")
    public String downloadResource(
            @ToolParam(description = "要下载资源的 URL") String url,
            @ToolParam(description = "可选：保存下载资源的期望文件名。如果未提供，将从 URL派生文件名。") String fileName) {

        String effectiveFileName = fileName;
        if (StrUtil.isBlank(effectiveFileName)) { // 使用 Hutool StrUtil.isBlank 进行空值判断
            try {
                effectiveFileName = FileUtil.getName(url); // Hutool 提取文件名
                if (StrUtil.isBlank(effectiveFileName) || effectiveFileName.contains("?") || effectiveFileName.contains("&")) {
                    effectiveFileName = "downloaded_file_" + System.currentTimeMillis();
                    logger.warn("无法从 URL派生有效文件名: {}. 使用生成的文件名: {}", url, effectiveFileName);
                }
            } catch (Exception e) {
                logger.error("从 URL派生文件名时出错: {}", url, e);
                effectiveFileName = "downloaded_file_" + System.currentTimeMillis();
            }
        }

        // 使用自定义方法清理文件名
        effectiveFileName = sanitizeFileName(effectiveFileName);
        if (effectiveFileName.length() > 200) { // 限制文件名长度
            effectiveFileName = effectiveFileName.substring(0, 200);
        }

        String fileDir = FileConstant.FILE_SAVE_DIR + "/download";
        // 确保最终的文件名不会因为清理而变得与临时文件模式冲突
        String tempFileNamePrefix = "temp_" + System.currentTimeMillis() + "_";
        String tempFilePath = fileDir + "/" + tempFileNamePrefix + effectiveFileName;
        String finalFilePath = fileDir + "/" + effectiveFileName;

        // 检查清理后的文件名是否与临时文件名的模式意外相同
        if (effectiveFileName.startsWith("temp_") && effectiveFileName.matches("^temp_\\d+_.*")) {
            logger.warn("清理后的文件名 '{}' 可能与临时文件模式冲突，尝试添加前缀。", effectiveFileName);
            finalFilePath = fileDir + "/final_" + effectiveFileName;
        }


        try {
            FileUtil.mkdir(fileDir);
            logger.info("尝试从 URL 下载资源: {} 到临时文件: {}", url, tempFilePath);

            long size = HttpRequest.get(url)
                    .setFollowRedirects(true)
                    .timeout(DEFAULT_TIMEOUT)
                    .header("User-Agent", "XWQEduAgent/1.0")
                    .execute()
                    .writeBody(new File(tempFilePath));

            if (size <= 0) {
                FileUtil.del(tempFilePath);
                logger.error("下载的文件为空或从 URL下载失败: {}", url);
                return "下载资源错误：下载的文件为空或从 " + url + " 下载失败";
            }

            // 检查最终路径是否已存在并且是一个目录（避免写入错误）
            File finalFile = new File(finalFilePath);
            if (finalFile.exists() && finalFile.isDirectory()) {
                FileUtil.del(tempFilePath); // 删除临时文件
                logger.error("无法保存文件，目标路径 '{}' 已存在并且是一个目录。", finalFilePath);
                return "下载资源错误：无法保存文件，目标路径 '" + finalFilePath + "' 已存在并且是一个目录。";
            }

            Files.move(Paths.get(tempFilePath), Paths.get(finalFilePath), StandardCopyOption.REPLACE_EXISTING);

            logger.info("资源成功下载到: {}. 大小: {} 字节", finalFilePath, size);
            return "资源成功下载到: " + finalFilePath + " (大小: " + FileUtil.readableFileSize(size) + ")";

        } catch (HttpException e) {
            FileUtil.del(tempFilePath);
            logger.error("从 URL {} 下载资源时发生 HTTP 错误: {}", url, e.getMessage(), e);
            return "下载资源错误：HTTP 请求失败。 " + e.getMessage();
        } catch (IORuntimeException e) {
            FileUtil.del(tempFilePath);
            logger.error("URL {} 下载或文件操作期间发生 IO 错误: {}", url, e.getMessage(), e);
            return "下载资源错误：IO 错误。 " + e.getMessage();
        } catch (Exception e) {
            FileUtil.del(tempFilePath);
            logger.error("从 URL {} 下载资源时发生意外错误: {}", url, e.getMessage(), e);
            return "下载资源错误：发生意外错误。 " + e.getMessage();
        }
    }
}